/* 
 * Cashbox is the legal property of its developers, whose names are listed in the copyright file included
 * with this source distribution.
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
 * General Public License as published by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
 * Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program; if not,
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#import "CBMainWindowController.h"

#import "CBSplitViewHandleHelper.h"

#import "CBAccountViewController.h"
#import "CBReportViewController.h"
#import "CBSourceListViewController.h"

#import "CBViewController.h"
#import "CBUndoController.h"

#import <Cashbox/CBReport.h>
#import <Cashbox/CBReportControllerProtocol.h>
#import <Cashbox/CBDataControllerProtocol.h>

#define DEFAULT_ACCOUNT_TABLE_WIDTH 	175
#define MIN_ACCOUNT_TABLE_WIDTH 		100
#define MAX_ACCOUNT_TABLE_WIDTH 		450

#define TITLE			@"name"
#define IMAGE			@"image"
#define ITEMS			@"arrangedObjects"
#define REPRESENTATIVE	@"representative"

static NSString *CBNewTransactionItemIdentifier = @"CBNewTransactionItemIdentifier";
static NSString *CBRemoveTransactionItemIdentifier = @"CBRemoveTransactionItemIdentifier";
static NSString *CBTransferTransactionItemIdentifier = @"CBTransferTransactionItemIdentifier";

static void *CBVisibleTableColumnContext = @"CBVisibleTableColumnContext";
static void *CBAvailableTableColumnContext = @"CBAvailableTableColumnContext";	

@interface CBMainWindowController (Private)

- (void)updateRightViewControllerForNewContent;

- (CBViewController <CBAutosave> *)rightViewController;
- (void)setRightViewController:(CBViewController <CBAutosave> *)controller;
- (void)setRightViewAutosaveName:(NSString *)name;

- (void)setRightView:(NSView *)view;
- (NSView *)rightView;

- (void)removeTableColumnObservers;
- (void)updateTableColumnsAndObservers;

@end

@implementation CBMainWindowController

+ (NSString *)nibName {
	return @"MainWindow";
}

- (void)dealloc {
	[rightViewController release];
	[sourceListViewController release];
	
	[toolbar release];
	[content release];
	
	[visibleTableColumns release];
	[availableTableColumns release];

	[super dealloc];
}

- (void)windowDidLoad {
	
	sourceListViewController = [[CBSourceListViewController alloc] init];
	[self bind:@"content"
	  toObject:sourceListViewController
   withKeyPath:@"selectionInformation"
	   options:nil]; // observe any changes to the source list

	NSView *sourceListView = (NSView *)[sourceListViewController view];
	[sourceListView setFrame:NSMakeRect(0, 0, [leftView frame].size.width, [leftView frame].size.height)];
	[leftView addSubview:sourceListView];
	
	// since the split view isn't a NSSplitView, make sure all the views fit properly
	NSEnumerator *enumer = [[splitView subviews] objectEnumerator];
	NSView *view;
	while (view = [enumer nextObject]) {
		NSEnumerator *subEnumer = [[view subviews] objectEnumerator];
		NSView *subview;
		while (subview = [subEnumer nextObject]) {
			[subview setFrameSize:NSMakeSize([view frame].size.width, [subview frame].size.height)];
		}
	}

	[splitView setDelegate:self];
	[handleHelper setSplitView:splitView];

	// set the toolbar
	toolbar = [[NSToolbar alloc] initWithIdentifier:@"CashboxWindow"];
	[toolbar setAllowsUserCustomization:YES];
	[toolbar setAutosavesConfiguration:YES];
	[toolbar setDelegate:self];
	[[self window] setToolbar:toolbar];
	[[self window] setDelegate:self];
}


#pragma mark undo support
// ----------------------------------------------------------------------------------------------------
// undo support
// ----------------------------------------------------------------------------------------------------

- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
	return [[cashbox undoController] defaultUndoManager];
}

#pragma mark autosavename
// ----------------------------------------------------------------------------------------------------
// autosavename
// ----------------------------------------------------------------------------------------------------

- (void)setAutosaveName:(NSString *)name {
	[[self window] setFrameAutosaveName:name];
	[splitView setPositionAutosaveName:[name stringByAppendingString:@" Split View"]];
	[sourceListViewController setAutosaveName:[name stringByAppendingString:@" Source List"]];
	[self setRightViewAutosaveName:name];
}

- (NSString *)autosaveName {
	return [[self window] frameAutosaveName];
}

- (void)setRightViewAutosaveName:(NSString *)name {
	if (rightViewController) {
		[rightViewController setAutosaveName:[name stringByAppendingString:@" Right View"]];
	}	
}

#pragma mark content
// ----------------------------------------------------------------------------------------------------
// content
// ----------------------------------------------------------------------------------------------------

- (void)setRightViewController:(CBViewController <CBAutosave> *)controller {
	if (rightViewController != controller) {
		[self willChangeValueForKey:@"rightViewController"];
		[rightViewController release];
		rightViewController = [controller retain];
		[self didChangeValueForKey:@"rightViewController"];
	}
}

- (CBViewController <CBAutosave> *)rightViewController {
	return rightViewController;
}

- (void)setRightView:(NSView *)view {
	if (rightView != view) {
		[self willChangeValueForKey:@"rightView"];
		[splitView replaceSubview:rightView with:view];
		rightView = view;
		[self didChangeValueForKey:@"rightView"];
	}
}

- (NSView *)rightView {
	return rightView;
}

- (void)setContent:(id)object {
	if (object != content) {
		[content release];
		content = [object retain];
		[self updateRightViewControllerForNewContent];
	}
}

- (id)content {
	return content;
}

- (void)updateRightViewControllerForNewContent {
	// content is bound to the source list selection and changes as it changes
	Class controllerClass = nil;
	SEL selector = NULL;
	id contentObject = [self content];
	
	if ([[contentObject objectForKey:CBSelectionTypeKey] intValue] == CBAccountSelectionType) {
		controllerClass = [CBAccountViewController class];
		selector =  @selector(setAccount:);
	} else if ([[contentObject objectForKey:CBSelectionTypeKey] intValue] == CBReportSelectionType) {
		controllerClass = [CBReportViewController class];
		selector =  @selector(setReport:);
	} else {
		[[NSException exceptionWithName:@"InvalidObject"
								 reason:[NSString stringWithFormat:@"CBCashboxWindowController received an "
										 "object in setContent: that it can't handle (description - %@)",
										 [contentObject description]]
							   userInfo:nil] raise];
	}
	
	if (![[self rightViewController] isKindOfClass:controllerClass]) {
		[self setRightViewController:[[[controllerClass alloc] init] autorelease]];
		[self setRightView:[[self rightViewController] view]];
	}
	[[self rightViewController] performSelector:selector
									 withObject:[contentObject objectForKey:CBSelectionObjectKey]];	
}

#pragma mark messages forwared to the right view
// ----------------------------------------------------------------------------------------------------
// messages forwared to the right view
// ----------------------------------------------------------------------------------------------------

- (IBAction)addTransaction:(id)sender {
	if ([self canAddTransaction]) {
		[rightViewController addTransaction:sender];
	}
}
- (BOOL)canAddTransaction {
	return rightViewController &&
		[rightViewController respondsToSelector:@selector(canAddTransaction)] &&
		[rightViewController canAddTransaction];
}

- (IBAction)addTransferTransaction:(id)sender {
	if ([self canAddTransferTransaction]) {
		[rightViewController addTransferTransaction:sender];
	}
}
- (BOOL)canAddTransferTransaction {
	return rightViewController &&
		[rightViewController respondsToSelector:@selector(canAddTransferTransaction)] &&
		[rightViewController canAddTransferTransaction];
}

- (IBAction)removeTransaction:(id)sender {
	if ([self canRemoveTransaction]) {
		[rightViewController removeTransaction:sender];
	}	
}
- (BOOL)canRemoveTransaction {
	return rightViewController &&
		[rightViewController respondsToSelector:@selector(canRemoveTransaction)] &&
		[rightViewController canRemoveTransaction];
}


#pragma report related
// ----------------------------------------------------------------------------------------------------
// report related
// ----------------------------------------------------------------------------------------------------

- (IBAction)addReport:(id)sender {
//	[NSApp beginSheet:addAccountPanel
//	   modalForWindow:[self window]
//		modalDelegate:nil
//	   didEndSelector:nil
//		  contextInfo:nil];
	
	//	[[[[cashbox dataController] managedObjectContext] undoManager] beginUndoGrouping];
	//Class transactionClass = [[[self account] class] transactionClass];
	
#warning display dialog
	Class reportType = [[[cashbox reportController] reportTypes] objectAtIndex:0];
	CBReport *report = [[[reportType alloc] init] autorelease];
	[report setName:@"Test Report"];
	[[[cashbox dataController] managedObjectContext] processPendingChanges];
	
//	CBReport *r = [[[transactionClass alloc] initAndInsertIntoAccount:[self account]] autorelease];
//	[transactions setSelectedObjects:[NSArray arrayWithObjects:t, nil]];
//	int editIndex = [[tableView tableColumns] indexOfObject:[[self dynamicTableColumns] firstObject]];
//	if (editIndex != NSNotFound) {
//		[tableView editColumn:editIndex row:[transactions selectionIndex] withEvent:nil select:YES];
//	} else { [tableView scrollRowToVisible:[transactions selectionIndex]]; }
	//	[[[[cashbox dataController] managedObjectContext] undoManager] endUndoGrouping];
	//	[[[[cashbox dataController] managedObjectContext] undoManager]
	//  setActionName:FSLocalizedString(@"New Transaction", @"Undo action name")];
}
- (BOOL)canAddReport {
	return TRUE;
}
- (IBAction)removeReport:(id)sender {
	
}
- (BOOL)canRemoveReport {
	return FALSE;
}


#pragma mark table columns
// ----------------------------------------------------------------------------------------------------
// table columns
// ----------------------------------------------------------------------------------------------------

- (NSArray *)visibleTableColumns {
	return visibleTableColumns;
}

- (void)setVisibleTableColumns:(NSArray *)columns {
	if (columns != visibleTableColumns) {
		[self willChangeValueForKey:@"visibleTableColumns"];
		[visibleTableColumns release];
		visibleTableColumns = [columns retain];
		[self didChangeValueForKey:@"visibleTableColumns"];
	}
}

- (NSArray *)availableTableColumns {
	return availableTableColumns;
}

- (void)setAvailableTableColumns:(NSArray *)columns {
	if (columns != availableTableColumns) {
		[self willChangeValueForKey:@"availableTableColumns"];
		[availableTableColumns release];
		availableTableColumns = [columns retain];
		[self didChangeValueForKey:@"availableTableColumns"];
	}
}

- (void)toggleTableColumnVisibility:(NSTableColumn *)column {
	if (rightViewController &&
		[rightViewController respondsToSelector:@selector(toggleTableColumnVisibility:)]) {
		[(id)rightViewController toggleTableColumnVisibility:column];
	}	
}

- (void)removeTableColumnObservers {
	// remove base on the same conditions that it was added on
	if (rightViewController && [rightViewController respondsToSelector:@selector(visibleTableColumns)]) {
		[rightViewController removeObserver:self forKeyPath:@"visibleTableColumns"];
	}
	
	// remove base on the same conditions that it was added on
	if (rightViewController && [rightViewController respondsToSelector:@selector(availableTableColumns)]) {
		[rightViewController removeObserver:self forKeyPath:@"availableTableColumns"];
	}
}

- (void)updateTableColumnsAndObservers {
	if (rightViewController && [rightViewController respondsToSelector:@selector(visibleTableColumns)]) {
		[rightViewController addObserver:self
							  forKeyPath:@"visibleTableColumns"
								 options:0
								 context:CBVisibleTableColumnContext];
		[self setVisibleTableColumns:[rightViewController visibleTableColumns]];
	} else {
		[self setVisibleTableColumns:nil];
	}
	
	if (rightViewController && [rightViewController respondsToSelector:@selector(availableTableColumns)]) {
		[rightViewController addObserver:self
							  forKeyPath:@"availableTableColumns"
								 options:0
								 context:CBAvailableTableColumnContext];
		[self setAvailableTableColumns:[rightViewController availableTableColumns]];
	} else {
		[self setAvailableTableColumns:nil];
	}
}

#pragma mark watching things change internally
// ----------------------------------------------------------------------------------------------------
// watching things change internally
// ----------------------------------------------------------------------------------------------------

- (void)willChangeValueForKey:(NSString *)key {
	
	if ([key isEqualToString:@"rightViewController"]) {
		// remove the observers that were added to watch for table column changes
		[self removeTableColumnObservers];
	}
	
	[super willChangeValueForKey:key];
}

- (void)didChangeValueForKey:(NSString *)key {
	
	if ([key isEqualToString:@"rightViewController"]) {
		// update the table columns shown for the window
		// and add ovservers to watch for when they change
		[self updateTableColumnsAndObservers];
		// set the autosave name for it as well
		[self setRightViewAutosaveName:[self autosaveName]];		
	}

	[super didChangeValueForKey:key];
}


#pragma mark bindings
// ----------------------------------------------------------------------------------------------------
// bindings
// ----------------------------------------------------------------------------------------------------

static void *ContentBindingContext = (void *)@"Content";

- (void)bind:(NSString *)binding
	toObject:(id)observableObject
 withKeyPath:(NSString *)keyPath
	 options:(NSDictionary *)options {
	if ([binding isEqualToString:@"content"]) {
		[observableObject addObserver:self
						   forKeyPath:keyPath
							  options:0
							  context:ContentBindingContext];
	} else {
		[super bind:binding toObject:observableObject withKeyPath:keyPath options:options];
	}
}

- (void)observeValueForKeyPath:(NSString *)keyPath
					  ofObject:(id)object
						change:(NSDictionary *)change
					   context:(void *)context {
	if (context == ContentBindingContext) {
		id new_obj = [object valueForKeyPath:keyPath];
		[self setValue:new_obj forKey:@"content"];
	} else if (context == CBVisibleTableColumnContext) {
		[self setVisibleTableColumns:[rightViewController visibleTableColumns]];
	} else if (context == CBAvailableTableColumnContext) {
		[self setAvailableTableColumns:[rightViewController availableTableColumns]];		
	}
}


#pragma mark split view delegate
// ----------------------------------------------------------------------------------------------------
// split view delegate
// ----------------------------------------------------------------------------------------------------

- (float)splitView:(NSSplitView *)sender constrainMinCoordinate:(float)proposedCoord ofSubviewAt:(int)offset {
	return MIN_ACCOUNT_TABLE_WIDTH;
}

- (float)splitView:(NSSplitView *)sender constrainMaxCoordinate:(float)proposedCoord ofSubviewAt:(int)offset {
	return MAX_ACCOUNT_TABLE_WIDTH;
}

	- (float)splitView:(NSSplitView *)sender
constrainSplitPosition:(float)proposedPosition
		   ofSubviewAt:(int)offset {
		
	if (abs(proposedPosition - DEFAULT_ACCOUNT_TABLE_WIDTH) < 20) { return DEFAULT_ACCOUNT_TABLE_WIDTH; }
	return proposedPosition;
}

- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize {
	NSArray *subviews = [sender subviews];
	if ([subviews count] == 2) {
		NSView *first = [subviews objectAtIndex:0];
		NSView *second = [subviews objectAtIndex:1];
		
		[first setFrameSize:NSMakeSize([first frame].size.width, [sender frame].size.height)];
		[second setFrameSize:
		 NSMakeSize([sender frame].size.width - [first frame].size.width - [sender dividerThickness],
					[sender frame].size.height)];
		
		[first setNeedsDisplay:TRUE];
		[second setNeedsDisplay:TRUE];
		[sender adjustSubviews];
	}
}

- (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subviews {
	return NO;
}

#pragma mark toolbar delegate
// ----------------------------------------------------------------------------------------------------
// toolbar delegate
// ----------------------------------------------------------------------------------------------------

- (NSArray *)toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar {
	return [NSArray arrayWithObjects:
		CBNewTransactionItemIdentifier,
		CBTransferTransactionItemIdentifier,
		CBRemoveTransactionItemIdentifier,
		NSToolbarPrintItemIdentifier,
		NSToolbarCustomizeToolbarItemIdentifier,
		NSToolbarFlexibleSpaceItemIdentifier,
		NSToolbarSpaceItemIdentifier,
		NSToolbarSeparatorItemIdentifier, nil];
}

- (NSArray *)toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar {
	return [NSArray arrayWithObjects:
		CBNewTransactionItemIdentifier,
		CBTransferTransactionItemIdentifier,
		CBRemoveTransactionItemIdentifier,
		NSToolbarFlexibleSpaceItemIdentifier,
		NSToolbarCustomizeToolbarItemIdentifier, nil];
}

- (BOOL)validateToolbarItem:(NSToolbarItem *)item {
	if ([[item itemIdentifier] isEqualToString:CBNewTransactionItemIdentifier] &&
		[self canAddTransaction]) {
		return YES;
	} else if ([[item itemIdentifier] isEqualToString:CBRemoveTransactionItemIdentifier] &&
			   [self canRemoveTransaction]) {
		return YES;
	} else if ([[item itemIdentifier] isEqualToString:CBTransferTransactionItemIdentifier] &&
			   [self canAddTransferTransaction]) {
		return YES;
	}
	return NO;
}

- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
	 itemForItemIdentifier:(NSString *)itemIdentifier
 willBeInsertedIntoToolbar:(BOOL)flag {
	
	NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
	
	if ([itemIdentifier isEqualToString:CBNewTransactionItemIdentifier]) {
		[toolbarItem setLabel:FSLocalizedString(@"New", nil)];
		[toolbarItem setPaletteLabel:FSLocalizedString(@"New Transaction", nil)];
		[toolbarItem setTarget:self];
		[toolbarItem setAction:@selector(addTransaction:)];
		[toolbarItem setImage:[NSImage imageNamed:@"add"]];
	} else if ([itemIdentifier isEqualToString:CBRemoveTransactionItemIdentifier]) {
		[toolbarItem setLabel:FSLocalizedString(@"Remove", nil)];
		[toolbarItem setPaletteLabel:FSLocalizedString(@"Remove Transaction", nil)];
		[toolbarItem setTarget:self];
		[toolbarItem setAction:@selector(removeTransaction:)];
		[toolbarItem setImage:[NSImage imageNamed:@"remove"]];
	} else if ([itemIdentifier isEqualToString:CBTransferTransactionItemIdentifier]) {
		[toolbarItem setLabel:FSLocalizedString(@"Transfer", nil)];
		[toolbarItem setPaletteLabel:FSLocalizedString(@"Create a transfer", nil)];
		[toolbarItem setTarget:self];
		[toolbarItem setAction:@selector(addTransferTransaction:)];
		[toolbarItem setImage:[NSImage imageNamed:@"transfer"]];		
	}
	return toolbarItem;
}

@end
